# enum 枚举
from enum import Enum, unique, auto, IntEnum, IntFlag


class Color(Enum):
    red = 1
    green = 2
    blue = 3


print(Color.red, repr(Color.red))  # Color.red <Color.red: 1>
print(type(Color.red))  # <enum 'Color'>
print(isinstance(Color.red, Color))  # True
print(Color.red.name)  # red
# 枚举成员可hash
apples = {}
apples[Color.red] = 'red delicious'
apples[Color.green] = 'granny smith'
print(apples)  # {<Color.red: 1>: 'red delicious', <Color.green: 2>: 'granny smith'}
print(Color(1), Color['red'])  # Color.red Color.red


# 确保唯一性
@unique
class Mistake(Enum):
    one = 1
    two = 2
    three = 3
    # four = 3 # 值为3的已存在，会报错


# 设备自动的值
class Color(Enum):
    red = auto()
    blue = auto()
    green = auto()


# 迭代
print(list(Color))  # [<Color.red: 1>, <Color.blue: 2>, <Color.green: 3>]

for name, member in Color.__members__.items():
    print(name, member)


# red Color.red
# blue Color.blue
# green Color.green


# 可以有其他成员和属性
class Mood(Enum):
    FUNKY = 1
    HAPPY = 3

    def describe(self):
        return self.name, self.value

    def __str__(self):
        return 'my custom str! {}'.format(self.value)

    @classmethod
    def favorite_mood(cls):
        return cls.HAPPY


print(Mood.favorite_mood())  # my custom str! 3
print(Mood.HAPPY.describe())  # ('HAPPY', 3)
print(str(Mood.FUNKY))  # my custom str! 1

# 功能性api,返回一个派生自Enum的类
Animal = Enum('Animal', 'ANT BEE CAT DOG')
print(Animal, Animal.ANT, Animal.ANT.value)  # <enum 'Animal'> Animal.ANT 1


# IntEnum 中的成员可与整数进行比较，类似于整数
class Shape(IntEnum):
    CIRCLE = 1
    SQUARE = 2


class Request(IntEnum):
    POST = 1
    GET = 2


print(Shape == 1, Shape.CIRCLE == 1, Shape.CIRCLE == Request.POST)  # False True True
print(int(Shape.SQUARE), ['a', 'b', 'c'][Shape.CIRCLE])  # 2 b
print([i for i in range(Shape.SQUARE)])  # [0, 1]


# IntFlag 成员可使用按位运算符， 进行组合且结果仍然为 IntFlag 成员
class Perm(IntFlag):
    R = 4
    W = 2
    X = 1
    RWX = 7


print(Perm.RWX, Perm.R | Perm.W, Perm.R + Perm.W)  # Perm.RWX Perm.R|W 6
print(Perm.R & Perm.X, bool(Perm.R & Perm.X))  # Perm.0 False
# 与 IntFlag 类似，Flag 成员可使用按位运算符 (&, |, ^, ~) 进行组合，与 IntFlag 不同的是它们不可与任何其它 Flag 枚举或 int 进行组合或比较
